package muhnes.sizoo.controlador;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.model.SelectItem;
import muhnes.sizoo.etl.PrimeFacesProgressIndicator;
import org.primefaces.context.RequestContext;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile;
import scriptella.configuration.ConfigurationFactory;
import scriptella.execution.EtlExecutor;
import scriptella.execution.EtlExecutorException;
import scriptella.execution.ExecutionStatistics;

/**
 * Clase que define los metodos que controlan la interfaz de importacion de informacion
 * @author Ricardo Orellana
 */
@ManagedBean(name = "importarBean")
@ViewScoped
public class ImportarBean implements Serializable {
    
    static {
        Map<String,String> temp = new HashMap<String,String>();
        temp.put("as400", "jdbc:as400://%s:%s/%s");
        temp.put("db2", "jdbc:db2://%s:%s/%s");
        temp.put("mysql", "jdbc:mysql://%s:%s/%s");
        temp.put("odbc", "jdbc:odbc://%s:%s/%s");
        temp.put("oracle", "jdbc:oracle:thin:@%s:%s:%s");
        temp.put("postgresql", "jdbc:postgresql://%s:%s/%s");
        temp.put("mssql", "jdbc:mssql:Tds://%s:%s/%s");
        temp.put("sybase", "jdbc:sybase:Tds://%s:%s/%s");
        mapeoUrl = Collections.unmodifiableMap(temp);
    }
    
    private final static Map<String,String> mapeoUrl; 
    
    enum TipoETL {
        INDEFINIDO,
        CSV,
        XML,
        SQL
    }
    
    private TipoETL tipoEtl;
    /*private String mapeoPhylum;
    private String mapeoClase;
    private String mapeoOrden;
    private String mapeoSuperfamilia;
    private String mapeoFamilia;
    private String mapeoGenero;
    private String mapeoEspecie;*/
    private String proveedorBD;
    private String hostBD;
    private String puertoBD;
    private String nombreBD;
    private String usuarioBD;
    private String contrasenyaBD;
    private String jdbcBD;
    private String consultaBD;
    private List<SelectItem> itemsEtl;
    private List<SelectItem> itemsProveedor;
    private String rutaArchivoSubido;
    
    /**
     * Constructor de la clase
     */
    public ImportarBean() {
        tipoEtl = TipoETL.INDEFINIDO;
        /*mapeoPhylum = "phylum";
        mapeoClase = "clase";
        mapeoOrden = "orden";
        mapeoSuperfamilia = "superfamilia";
        mapeoFamilia = "familia";
        mapeoGenero = "genero";
        mapeoEspecie = "especie";*/
    }
    
    public void validarAcceso(ComponentSystemEvent evento) throws IOException {
        //boolean accesoPermitido = sesionBean.verificarPermiso("acceder", vistaProtegida); 
        
        /*if( !accesoPermitido ) {
            FacesContext contexto = FacesContext.getCurrentInstance();
            String nombreContexto = contexto.getExternalContext().getRequestContextPath();
            String urlError = nombreContexto + "/paginas/errores/error.xhtml";
            contexto.getExternalContext().redirect(urlError);
        }*/
    }
    
    /**
     * Getter de tipoEtl
     *  
     */
    public TipoETL getTipoEtl() {
        return tipoEtl;
    }

    /**
     * Setter de tipoEtl
     * @param tipoEtl 
     */
    public void setTipoEtl(TipoETL tipoEtl) {
        this.tipoEtl = tipoEtl;
    }

    /*public String getMapeoPhylum() {
        return mapeoPhylum;
    }

    public void setMapeoPhylum(String mapeoPhylum) {
        this.mapeoPhylum = mapeoPhylum;
    }

    public String getMapeoClase() {
        return mapeoClase;
    }

    public void setMapeoClase(String mapeoClase) {
        this.mapeoClase = mapeoClase;
    }

    public String getMapeoOrden() {
        return mapeoOrden;
    }

    public void setMapeoOrden(String mapeoOrden) {
        this.mapeoOrden = mapeoOrden;
    }

    public String getMapeoSuperfamilia() {
        return mapeoSuperfamilia;
    }

    public void setMapeoSuperfamilia(String mapeoSuperfamilia) {
        this.mapeoSuperfamilia = mapeoSuperfamilia;
    }

    public String getMapeoFamilia() {
        return mapeoFamilia;
    }

    public void setMapeoFamilia(String mapeoFamilia) {
        this.mapeoFamilia = mapeoFamilia;
    }

    public String getMapeoGenero() {
        return mapeoGenero;
    }

    public void setMapeoGenero(String mapeoGenero) {
        this.mapeoGenero = mapeoGenero;
    }

    public String getMapeoEspecie() {
        return mapeoEspecie;
    }

    public void setMapeoEspecie(String mapeoEspecie) {
        this.mapeoEspecie = mapeoEspecie;
    }*/

    /**
     * 
     * Getter de proveedorBD
     */
    public String getProveedorBD() {
        return proveedorBD;
    }

    public void setProveedorBD(String proveedorBD) {
        this.proveedorBD = proveedorBD;
    }
    
    /**
     * 
     * Getter de  hostBD
     */
    public String getHostBD() {
        return hostBD;
    }

    /**
     * Setter de hostBD
     * @param hostBD 
     */
    public void setHostBD(String hostBD) {
        this.hostBD = hostBD;
    }
    
    /**
     * 
     * Getter de  puertoBD
     */
    public String getPuertoBD() {
        return puertoBD;
    }

    /**
     * Setter de puertoBD
     * @param puertoBD 
     */
    public void setPuertoBD(String puertoBD) {
        this.puertoBD = puertoBD;
    }
    
    /**
     * 
     * Getter de nombreBD 
     */
    public String getNombreBD() {
        return nombreBD;
    }

    /**
     * Setter de nombreBD
     * @param nombreBD 
     */
    public void setNombreBD(String nombreBD) {
        this.nombreBD = nombreBD;
    }

    /**
     * 
     * Gett de usuarioDB  
     */
    public String getUsuarioBD() {
        return usuarioBD;
    }

    /**
     * Setter de usuarioBD
     * @param usuarioBD 
     */
    public void setUsuarioBD(String usuarioBD) {
        this.usuarioBD = usuarioBD;
    }

    /**
     * 
     * Getter de  contrasenyaBD
     */
    public String getContrasenyaBD() {
        return contrasenyaBD;
    }

    /**
     * Setter de contrasenyaBD
     * @param contrasenyaBD 
     */
    public void setContrasenyaBD(String contrasenyaBD) {
        this.contrasenyaBD = contrasenyaBD;
    }
    
    /**
     * Metodo que recupera la conexion JDBC
     *  
     */
    public String getJdbcBD() {
        if( proveedorBD != null && !proveedorBD.isEmpty() ) {
            jdbcBD = mapeoUrl.get(proveedorBD);
            String host = hostBD != null && !hostBD.isEmpty() ? hostBD : "host";
            String puerto = puertoBD != null && !puertoBD.isEmpty() ? puertoBD : "puerto";
            String nombre = nombreBD != null && !nombreBD.isEmpty() ? nombreBD : "nombre";
            jdbcBD = String.format(jdbcBD, host, puerto, nombre);
        }
        return jdbcBD;
    }

    /**
     * Setter de jdbcBD
     * @param jdbcBD 
     */
    public void setJdbcBD(String jdbcBD) {
        this.jdbcBD = jdbcBD;
    }
    
    /**
     * Getter de consultaBD
     *  
     */
    public String getConsultaBD() {
        return consultaBD;
    }

    /**
     * Setter de consultaBD
     * @param consultaBD 
     */
    public void setConsultaBD(String consultaBD) {
        this.consultaBD = consultaBD;
    }
    
    /**
     * Metodo que devuelve una lista que contiene los archivos a importar
     * @return objeto list
     */
    public List<SelectItem> getItemsEtl() {
        if( itemsEtl == null ) {
            itemsEtl = new ArrayList<SelectItem>();
            itemsEtl.add(new SelectItem(TipoETL.CSV,"Archivo CSV"));
            itemsEtl.add(new SelectItem(TipoETL.XML,"Archivo XML"));
            itemsEtl.add(new SelectItem(TipoETL.SQL,"Conexión SQL"));
        }
        return itemsEtl;
    }

    /**
     * Metodo que devuelve una lista de proveedores
     *  
     */
    public List<SelectItem> getItemsProveedor() {
        if( itemsProveedor == null ) {
            itemsProveedor = new ArrayList<SelectItem>();
            itemsProveedor.add( new SelectItem(
                "as400",
                "AS400"
            ));
            itemsProveedor.add( new SelectItem(
                "db2",
                "DB2"
            ));
            itemsProveedor.add( new SelectItem(
                "mysql",
                "MySQL"
            ));
            itemsProveedor.add( new SelectItem(
                "odbc",
                "ODBC"
            ));
            itemsProveedor.add( new SelectItem(
                "oracle",
                "Oracle"
            ));
            itemsProveedor.add( new SelectItem(
                "postgresql",
                "Postgresql"
            ));
            itemsProveedor.add( new SelectItem(
                "mssql",
                "SQL Server"
            ));
            itemsProveedor.add( new SelectItem(
                "sybase",
                "Sybase"
            ));
        }
        return itemsProveedor;
    }
 
    /**
     * Metodo que carga el archivo que se desea importar
     * @param evento 
     */
    public void cargarArchivo( FileUploadEvent evento ) {  
        {
            BufferedWriter escritor = null;
            try {
                UploadedFile archivo = evento.getFile();
                FacesContext contexto = FacesContext.getCurrentInstance();
                String uuid = UUID.randomUUID().toString();
                String ruta = contexto.getExternalContext().getRealPath("/WEB-INF/etl/" + uuid + ".etl");
                escritor = new BufferedWriter(new FileWriter(ruta));
                escritor.write(new String(archivo.getContents()));
                escritor.close();
                rutaArchivoSubido = ruta;
            } catch (IOException ex) {
                Logger.getLogger(ImportarBean.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    } 
    
    /**
     * Metodo que ejecuta la conversion ETL
     */
    public void ejecutarEtl() {
        
        try {
            Map<String,String> parametros = new HashMap<String,String>();
            
            if( tipoEtl == TipoETL.CSV || tipoEtl == TipoETL.XML ) {
                parametros.put( "ruta", rutaArchivoSubido );
            }
            else if( tipoEtl == TipoETL.SQL ) {
                parametros.put( "driver", proveedorBD );
                parametros.put( "jdbc", jdbcBD );
                parametros.put( "usuario", usuarioBD );
                parametros.put( "contrasenya", contrasenyaBD );
                parametros.put( "consulta", consultaBD );
            }
            else {
                return;
            }
            
            /*parametros.put( "phylum", mapeoPhylum );
            parametros.put( "clase", mapeoClase );
            parametros.put( "orden", mapeoOrden );
            parametros.put( "superfamilia", mapeoSuperfamilia );
            parametros.put( "familia", mapeoFamilia );
            parametros.put( "genero", mapeoGenero );
            parametros.put( "especie", mapeoEspecie );*/
            
            FacesContext contexto = FacesContext.getCurrentInstance();
            String tipo = tipoEtl.toString().toLowerCase();
            String rutaRelativa = "/WEB-INF/etl/importacion-" + tipo + ".etl.xml";
            String scriptEtl = contexto.getExternalContext().getRealPath( rutaRelativa );
            URL urlArchivo = new File( scriptEtl ).toURI().toURL();
            
            EtlExecutor etl = new EtlExecutor();
            ConfigurationFactory configuracion = new ConfigurationFactory();
            configuracion.setResourceURL( urlArchivo );
            configuracion.setExternalParameters( parametros );
            etl.setConfiguration( configuracion.createConfiguration() );
            PrimeFacesProgressIndicator progreso = new PrimeFacesProgressIndicator("Sizoo:");
            ExecutionStatistics estadisticas = etl.execute( progreso );
        } catch (MalformedURLException ex) {
            Logger.getLogger(ImportarBean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (EtlExecutorException ex) {
            Logger.getLogger(ImportarBean.class.getName()).log(Level.SEVERE, null, ex);
        } 
        finally {
            RequestContext contexto = RequestContext.getCurrentInstance();
            contexto.execute("cargaWgt.hide()");
        }
        
    }
    
    public void cancelarEtl() {
        
    }
    
}
